package com.longway.common.controller;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.core.Controller;
import com.jfinal.core.NotAction;
import com.jfinal.json.FastJson;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.ehcache.CacheKit;
import com.longway.common.constant.Const;
import com.longway.common.kit.SignKit;
import com.longway.common.kit.SqlKit;
import com.longway.common.model.BaseDept;
import com.longway.common.model.BaseUser;
import com.longway.common.vo.JqGrid;
import com.longway.core.toolbox.Func;
import com.longway.core.toolbox.support.SqlKeyword;

import java.util.*;

/**
 * 基础控制器，方便获取登录信息
 * <p>
 * 警告：由于 BaseController 中声明了 Account loginAccount 属性，
 * 所以不能使用 FastControllerFactory 这类回收 Controller 的用法
 * 在 jfinal 3.5 发布以后，可以通过继承 _clear_() 方法来清除属性中的值
 * 才能使用 FastControllerFactory
 * 用户自己的 Controller 也是同样的道理
 * <p>
 * 注意：
 * 需要 LoginSessionInterceptor 配合，该拦截器使用
 * setAttr("loginAccount", ...) 事先注入了登录账户
 * 否则即便已经登录，该控制器也会认为没有登录
 * @author Administrator
 */
public class BaseController extends Controller implements Const {

    /**
     * 警告：由于这个属性的存在，不能直接使用 FastControllerFactory，除非使用 jfinal 3.5
     * 并覆盖父类中的 _clear_() 方法清除本类中与父类中的属性值，详情见本类中的
     * protected void _clear_() 方法
     * <p>
     * 原因是 FastControllerFactory 是回收使用 controller 对象的，所以要在 _clear()_
     * 中清除上次使用时的属性值
     */
    private BaseUser loginAccount = null;

    @Override
    protected void _clear_() {
        this.loginAccount = null;
        super._clear_();
    }

    @NotAction
    public BaseUser getLoginAccount() {
        if (loginAccount == null) {
            loginAccount = getAttr(Const.loginAccountCacheName);
            if (loginAccount != null && !loginAccount.isStatusOk()) {
                throw new IllegalStateException("当前用户状态不允许登录，status = " + loginAccount.getStatus());
            }
        }
        return loginAccount;
    }

    @NotAction
    public BaseDept getBaseDept() {
        BaseUser baseUser = getLoginAccount();
        //优先从缓存中取，未命中缓存则从数据库取
        Long deptId = baseUser.getDeptId();
        BaseDept baseDept = CacheKit.get(Const.DEPT_CACHE, "findById_" + deptId);
        if (baseDept == null) {
            Record deptR = Db.findFirst("select * from base_dept where id = ?", deptId);
            baseDept = new BaseDept();
            baseDept.put(deptR);
            if (baseDept != null) {
                CacheKit.put(Const.DEPT_CACHE, "findById_" + deptId, baseDept);
            }
        }
        return baseDept;
    }

    @NotAction
    public boolean isLogin() {
        return getLoginAccount() != null;
    }


    @NotAction
    public boolean notLogin() {
        return !isLogin();
    }

    /**
     * 获取登录账户id
     * 确保在 FrontAuthInterceptor 之下使用，或者 isLogin() 为 true 时使用
     * 也即确定已经是在登录后才可调用
     */
    @NotAction
    public Long getLoginAccountId() {
        return getLoginAccount().getId();
    }

    @NotAction
    public boolean isPjaxRequest() {
        return "true".equalsIgnoreCase(getHeader("X-PJAX"));
    }

    @NotAction
    public boolean isAjaxRequest() {
        return "XMLHttpRequest".equalsIgnoreCase(getHeader("X-Requested-With"));
    }

    @NotAction
    public <E> JqGrid<E> getJgGridJson(Page<E> page) {
        return new JqGrid<E>(page.getList(), page.getTotalPage(), getParaToInt("page", 1), page.getTotalRow(), "ok");
    }

    @NotAction
    public Ret ajaxSucess(Object data) {
        return Ret.ok("code", 0).set("msg", "success").set("data", data);
    }

    @NotAction
    public Map<String, Object> getJsonData() {
        String json = getRawData();
        return FastJson.getJson().parse(json, Map.class);
    }

    @NotAction
    public Object getJsonParamByKey(String key) {
        Map<String, Object> param = getJsonData();
        return param.get(key);
    }

    @NotAction
    private void parseOrderAndExwhere(Kv param, String sort, String order, String exwhere) {
        if (!Func.isAllEmpty(sort, order)) {
            param.set("orderBy", "order By " + sort + " " + order);
        }
        if (!Func.isEmpty(exwhere)) {
            Map<String, String> mapexwhere = SqlKeyword.getSqlMap(exwhere);
            for (String key : mapexwhere.keySet()) {
                param.set(key, mapexwhere.get(key));
            }
        }
    }

    @NotAction
    private Map<String, Map<String, String>> parseCond(String where, boolean safe) {
        List<JSONObject> params = SqlKeyword.getSqlParams(where);
        Map<String, Map<String, String>> map = new LinkedHashMap<String, Map<String, String>>();
        String index, expre, value, connector, groupname = "";
        //获取有分组标志的sql条件
        Map<String, List<JSONObject>> groupParams = new HashMap<>();
        for (JSONObject param : params) {
            groupname = param.getString("group");
            if (groupParams.get(groupname) == null) {
                groupParams.put(groupname, new ArrayList<JSONObject>());
            }
            groupParams.get(groupname).add(param);
        }
        for (String gname : groupParams.keySet()) {
            List<JSONObject> groupLP = groupParams.get(gname);
            Map<String, String> group = new LinkedHashMap<String, String>();
            for (int i = 0; i < groupLP.size(); i++) {
                JSONObject param = groupLP.get(i);
                index = param.getString("index");
                if (safe) {
                    if (SqlKit.checkSQLInject(index)) {
                        throw new IllegalArgumentException(index + " column is not Illegal.");
                    }
                }
                value = param.getString("value");
                expre = param.getString("expre");
                connector = param.getString("connector");
                if ("or".equals(connector)) {
                    group.put(" or " + index + " " + expre, value);
                } else {
                    group.put(index + " " + expre, value);
                }
            }
            map.put(gname, group);
        }
        return map;
    }

    /**
     * where 前端传递时进行了两次编码
     * exwhere 前端传递时进行了一次编码
     *
     * @return
     */
    @NotAction
    public Kv getSqlPara() {
        String signOrign = getHeader("sign");
        Map<String, String> params = getParamsMap();
        boolean safe = SignKit.verifySign(params, signOrign);
        if (safe) {
            String where = params.get("where");
            where = where == null ? "" : where;
            String sidx = params.get("sidx");
            String sord = params.get("sord");
            String sort = params.get("sort");
            String order = params.get("order");
            order = order == null ? "" : order;
            String exwhere = params.get("exwhere");
            exwhere = exwhere == null ? "" : exwhere;
            if (StrKit.notBlank(sidx)) {
                sort = sidx + " " + sord + (StrKit.notBlank(sort) ? ("," + sort) : "");
            }
            Map<String, Map<String, String>> map = parseCond(where, false);
            Kv param = Kv.by("cond", map);
            parseOrderAndExwhere(param, sort, order, exwhere);
            return param;
        }
        return null;
    }

    @NotAction
    public Map<String, String> getParamsMap() {
        Map<String, String[]> params = getParaMap();
        Map<String, String> pms = new HashMap<String, String>();
        for (String key : params.keySet()) {
            pms.put(key, params.get(key)[0]);
        }
        return pms;
    }


    @NotAction
    public Kv getSqlParaSafe() {
        String where = getPara("where", "");
        String sidx = getPara("sidx", "");
        String sord = getPara("sord", "");
        String sort = getPara("sort", "");
        String order = getPara("order", "");
        String exwhere = getPara("exwhere", "");
        if (StrKit.notBlank(sidx)) {
            sort = sidx + " " + sord + (StrKit.notBlank(sort) ? ("," + sort) : "");
        }
        Map<String, Map<String, String>> map = parseCond(where, true);
        Kv param = Kv.by("cond", map);
        parseOrderAndExwhere(param, sort, order, exwhere);
        return param;
    }

    @NotAction
    public Map<String, String> getSqlParaCustom() {
        String where = getPara("where", "");
        Map<String, String> map = SqlKeyword.getSqlMap(where);
        return map;
    }
}


